package com.ruoyi.ring.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.enums.TimeUnitEnums;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.ring.domain.RingBloodOxygen;
import com.ruoyi.ring.domain.RingBloodOxygenDetail;
import com.ruoyi.ring.domain.RingSleepDetail;
import com.ruoyi.ring.domain.dto.GeneralSecondDTO;
import com.ruoyi.ring.domain.dto.RingSleepDetailInfoDTO;
import com.ruoyi.ring.domain.vo.*;
import com.ruoyi.ring.mapper.RingBloodOxygenDetailMapper;
import com.ruoyi.ring.mapper.RingBloodOxygenMapper;
import com.ruoyi.ring.mapper.RingSleepDetailMapper;
import com.ruoyi.ring.service.IBloodOxygenSecondService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class BloodOxygenSecondServiceImpl implements IBloodOxygenSecondService {
    @Resource
    private RingSleepDetailMapper sleepDetailMapper;
    @Resource
    private RingBloodOxygenMapper bloodOxygenMapper;
    @Resource
    private RingBloodOxygenDetailMapper bloodOxygenDetailMapper;

    @Override
    public List<CalendarResultVO> queryCalendarList(GeneralSecondDTO secondDTO) {
        //自动测量
        List<RingBloodOxygen> bloodOxygenList = bloodOxygenMapper.selectRingBloodOxygenList(Builder.of(RingBloodOxygen::new).with(RingBloodOxygen::setDeviceSn,secondDTO.getDeviceSn()).build());
        List<CalendarResultVO> resultVOS = Convert.toList(CalendarResultVO.class,bloodOxygenList);
        ZoneId zoneId = ZoneId.systemDefault();
        List<CalendarResultVO> list = resultVOS.stream()
                .collect(Collectors.toMap(
                        vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate(),
                        Function.identity(),
                        (existing, replacement) -> existing
                ))
                .values()
                .stream()
                // 使用Comparator.comparing指定按日期正序
                .sorted(Comparator.comparing(vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate()))
                .collect(Collectors.toList());
        return list;
    }

    @Override
    public GeneralAverageVO queryBloodOxygenAverage(GeneralSecondDTO secondDTO) {
        GeneralAverageVO averageVO = new GeneralAverageVO();
        //自动测量
        List<RingBloodOxygen> bloodOxygenList = bloodOxygenMapper.queryRingBloodOxygenList(secondDTO);
        List<Integer> bloodOxygenInfoList = new ArrayList<>();
        int average = 0;
        int maxValue;
        int minValue;
        List<GeneralAverageVO.ManualInfoVO> manualInfoVOList = new ArrayList<>();
        List<GeneralAverageVO.AutomaticInfoVO> automaticInfoVOList = new ArrayList<>();
        if("1".equals(secondDTO.getType())){
            //睡眠信息
            RingSleepDetail sleepDetail = sleepDetailMapper.querySleepInfoDetail(Builder.of(RingSleepDetailInfoDTO::new).
                    with(RingSleepDetailInfoDTO::setDeviceSn, secondDTO.getDeviceSn()).
                    with(RingSleepDetailInfoDTO::setDailyValue, secondDTO.getRecordDate()).build());
            if(sleepDetail != null) {
                averageVO.setEndTime(DateUtils.convertDateTimeToHHMM(sleepDetail.getEndDate()));
            }
            if(bloodOxygenList.size() > 0) {
                RingBloodOxygen ringBloodOxygen = bloodOxygenList.get(0);
                String[] bloodOxygen = ringBloodOxygen.getBloodList().replace("null", "0").replace("255", "0").split(",");//转成String数组
                bloodOxygenInfoList = Arrays.stream(bloodOxygen).map(Integer::parseInt).collect(Collectors.toList());
                average = Convert.toInt(bloodOxygenInfoList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
                int timeInterval = 24*60/bloodOxygenInfoList.size();
                for(int i = 0; i< bloodOxygenInfoList.size(); i++){
                    GeneralAverageVO.AutomaticInfoVO automaticInfoVO = new GeneralAverageVO.AutomaticInfoVO();
                    int bo = bloodOxygenInfoList.get(i);
                    // 计算当前时间（分钟）：初始0分钟，每次增加5分钟
                    int minutes = i * timeInterval;
                    // 格式化时间为HH:MM格式（补前导零）
                    automaticInfoVO.setCode(DateUtils.convertMinutesToHHMM(minutes));
                    automaticInfoVO.setValue(bo);
                    automaticInfoVOList.add(automaticInfoVO);
                }
                averageVO.setAutomaticInfoVOS(automaticInfoVOList);
            }
            //手动测量
            List<RingBloodOxygenDetail> bloodOxygenDetailList = bloodOxygenDetailMapper.queryRingBloodOxygenDetailList(secondDTO);
            for (RingBloodOxygenDetail detail : bloodOxygenDetailList){
                int value = detail.getBloodOxygen();
                GeneralAverageVO.ManualInfoVO manualInfoVO = new GeneralAverageVO.ManualInfoVO();
                manualInfoVO.setCode(DateUtils.convertDateTimeToHHMM(detail.getDailyValue()));
                manualInfoVO.setValue(Convert.toStr(value));
                manualInfoVOList.add(manualInfoVO);
                bloodOxygenInfoList.add(value);
            }
            maxValue = bloodOxygenInfoList.stream().filter(num -> num != 0).max(Integer::compare).orElse(0);
            minValue = bloodOxygenInfoList.stream().filter(num -> num != 0).min(Integer::compare).orElse(0);
            averageVO.setMaxValue(maxValue);
            averageVO.setMinValue(minValue);
            averageVO.setRecordDate(DateUtils.dateTimeChinese(secondDTO.getRecordDate()));
            averageVO.setWeekName(DateUtils.queryWeekday(secondDTO.getRecordDate()));
        }else {
            List<Integer> total = new ArrayList<>();
            for (RingBloodOxygen ringBloodOxygen : bloodOxygenList){
                GeneralAverageVO.AutomaticInfoVO automaticInfoVO = new GeneralAverageVO.AutomaticInfoVO();
                String[] bloodOxygen = ringBloodOxygen.getBloodList().replace("null", "0").replace("255", "0").split(",");//转成String数组
                List<Integer> bloodOxygens = Arrays.stream(bloodOxygen).map(Integer::parseInt).collect(Collectors.toList());
                total.addAll(bloodOxygens);
                // 计算小于90的元素总数
                int countLessThan90 = Convert.toInt(bloodOxygens.stream().filter(num -> num < 90 && num > 0).count());
                if("2".equals(secondDTO.getType())){
                    automaticInfoVO.setCode(DateUtils.convertDateToMMdd(ringBloodOxygen.getDailyValue()));
                }
                if("3".equals(secondDTO.getType())){
                    automaticInfoVO.setCode(DateUtils.queryMonthday(ringBloodOxygen.getDailyValue()));
                }
                maxValue = bloodOxygens.stream().filter(num -> num != 0).max(Integer::compare).orElse(0);
                minValue = bloodOxygens.stream().filter(num -> num != 0).min(Integer::compare).orElse(0);
                automaticInfoVO.setMaxValue(maxValue);
                automaticInfoVO.setMinValue(minValue);
                automaticInfoVO.setNumber(countLessThan90);
                automaticInfoVOList.add(automaticInfoVO);
            }
            average = Convert.toInt(total.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
            Date dateStart = TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType()) ? DateUtils.getWeekStart(secondDTO.getRecordDate(), ZoneId.systemDefault()) : DateUtils.getMonthStart(secondDTO.getRecordDate(), ZoneId.systemDefault());
            Date dateEnd = TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType()) ? DateUtils.getWeekEnd(secondDTO.getRecordDate(), ZoneId.systemDefault()) : DateUtils.getMonthEnd(secondDTO.getRecordDate(), ZoneId.systemDefault());
            averageVO.setDateStart(DateUtils.dateTimeChinese(dateStart) + "，" + DateUtils.queryWeekday(dateStart));
            averageVO.setDateEnd(DateUtils.dateTimeChinese(dateEnd) + "，" + DateUtils.queryWeekday(dateEnd));
        }
        averageVO.setAverage(average);
        averageVO.setManualInfoVOS(manualInfoVOList);
        averageVO.setAutomaticInfoVOS(automaticInfoVOList);
        return averageVO;
    }

    @Override
    public BloodOxygenMonitorVO queryBloodOxygenMonitor(GeneralSecondDTO secondDTO) {
        BloodOxygenMonitorVO monitorVO = new BloodOxygenMonitorVO();
        //睡眠信息
        List<RingSleepDetail> sleepDetailList = sleepDetailMapper.querySleepInfo(Builder.of(RingSleepDetailInfoDTO::new).
                with(RingSleepDetailInfoDTO::setDeviceSn, secondDTO.getDeviceSn()).
                with(RingSleepDetailInfoDTO::setDailyValue, secondDTO.getRecordDate()).
                with(RingSleepDetailInfoDTO::setType, secondDTO.getType()).build());
        List<RingBloodOxygen> bloodOxygenList = bloodOxygenMapper.queryRingBloodOxygenList(secondDTO);
        // 血氧饱和度平均值 */
        int bloodOxygenAverage = 0;
        // 最低血氧饱和度 */
        int minBloodOxygen = 0;
        // 血氧饱和度占比 */
        int bloodOxygenRate = 0;
        // 有效测量次数 */
        int effectiveMeasurement = 0;
        // <90的次数 */
        int exceptionCount = 0;
        if("1".equals(secondDTO.getType())){
            if(sleepDetailList.size() > 0 && bloodOxygenList.size() > 0){
                RingSleepDetail ringSleepDetail = sleepDetailList.get(0);
                RingBloodOxygen ringBloodOxygen = bloodOxygenList.get(0);
                String strValue = ringBloodOxygen.getBloodList().replace("null", "0").replace("255","0");
                // 遍历所有数据点
                List<Integer> valueList = Arrays.stream(strValue.split(","))
                        .map(String::trim) // 去除每个元素前后的空格
                        .map(Integer::parseInt) // 转换为整数
                        .collect(Collectors.toList());
                int timeInterval = 24*60/valueList.size();

                List<Integer> boList = queryValue(secondDTO.getRecordDate(),timeInterval,valueList,ringSleepDetail);
                bloodOxygenAverage = Convert.toInt(boList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
                minBloodOxygen = boList.stream().filter(num -> num != 0) .min(Integer::compare).orElse(0);
                effectiveMeasurement = boList.size();
                exceptionCount = Convert.toInt(boList.stream().filter(num -> num != 0 && num < 90).count());
                bloodOxygenRate = Convert.toInt(Convert.toDouble(exceptionCount) / Convert.toDouble(ringSleepDetail.getTotalTime()+ringSleepDetail.getAwakeTime()) * 100);
            }
        }else {
            if(sleepDetailList.size() > 0 && bloodOxygenList.size() > 0){
                List<Integer> boList = new ArrayList<>();
                double totalTime = 0;
                double exceptionCountTime = 0;
                for (RingSleepDetail ringSleepDetail : sleepDetailList){
                    RingBloodOxygen ringBloodOxygen = bloodOxygenList.stream().filter(bo -> bo.getDailyValue().getTime() == ringSleepDetail.getDailyValue().getTime()).findFirst().orElse(null);
                    if(ringBloodOxygen != null){
                        String strValue = ringBloodOxygen.getBloodList().replace("null", "0").replace("255","0");
                        // 遍历所有数据点
                        List<Integer> valueList = Arrays.stream(strValue.split(","))
                                .map(String::trim) // 去除每个元素前后的空格
                                .map(Integer::parseInt) // 转换为整数
                                .collect(Collectors.toList());
                        int timeInterval = 24*60/valueList.size();
                        List<Integer> list = queryValue(ringSleepDetail.getDailyValue(),timeInterval,valueList,ringSleepDetail);
                        boList.addAll(list);
                        totalTime += Convert.toDouble(ringSleepDetail.getTotalTime()+ringSleepDetail.getAwakeTime());
                        exceptionCountTime += (Convert.toDouble(boList.stream().filter(num -> num != 0 && num < 90).count()) * timeInterval);
                    }
                }
                bloodOxygenAverage = Convert.toInt(boList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
                minBloodOxygen = boList.stream().filter(num -> num != 0) .min(Integer::compare).orElse(0);
                bloodOxygenRate = Convert.toInt(exceptionCountTime / totalTime * 100);
//                effectiveMeasurement = boList.size();
//                exceptionCount = Convert.toInt(boList.stream().filter(num -> num != 0 && num < 90).count());
            }
        }
        monitorVO.setBloodOxygenRate(bloodOxygenRate);
        monitorVO.setBloodOxygenAverage(bloodOxygenAverage);
        monitorVO.setMinBloodOxygen(minBloodOxygen);
        monitorVO.setEffectiveMeasurement(effectiveMeasurement);
        monitorVO.setExceptionCount(exceptionCount);
        return monitorVO;
    }

    @Override
    public  List<GeneralInfoListVO> queryBloodOxygenInfoList(GeneralSecondDTO secondDTO) {
        List<GeneralInfoListVO> list = new ArrayList<>();
        List<GeneralGroupVO> groupVOList = bloodOxygenDetailMapper.queryBloodOxygenInfoList(secondDTO);
        for (GeneralGroupVO group : groupVOList) {
            GeneralInfoListVO infoListVO = new GeneralInfoListVO();
//            infoListVO.setDateStart(group.getDateStart());
//            infoListVO.setDateEnd(group.getDateEnd());
            infoListVO.setDailyValue(group.getDailyValue());
            infoListVO.setWeekName(group.getWeekName());
            String groupData = group.getGroupData(); // 包含多条记录的JSON数组
            // 解析JSON数组为具体的实体类（假设有子实体类 BloodOxygenDetail）
            if(groupData != null){
                JSONArray jsonArray = JSONArray.parseArray(groupData);
                List<JsonObjectVO> jsonObjectVOList = jsonArray.toJavaList(JsonObjectVO.class);
//                infoListVO.setJsonObjectVOList(jsonObjectVOList.stream().sorted().collect(Collectors.toList()));
                jsonObjectVOList = jsonObjectVOList.stream().sorted(Comparator.comparingLong(JsonObjectVO::getId).reversed()).collect(Collectors.toList());
                infoListVO.setJsonObjectVOList(jsonObjectVOList);

            }
            list.add(infoListVO);
        }
        return list;
    }

    @Override
    public GeneralDetailListVO queryBloodOxygenDetail(Long id) {
        RingBloodOxygenDetail bloodOxygenDetail = bloodOxygenDetailMapper.selectRingBloodOxygenDetailById(id);
        GeneralDetailListVO bloodOxygenDetailVO = Convert.convert(GeneralDetailListVO.class,bloodOxygenDetail);
        bloodOxygenDetailVO.setGeneralValue(bloodOxygenDetail.getBloodOxygen());
        bloodOxygenDetailVO.setWeek(DateUtils.queryWeekday(bloodOxygenDetail.getDailyValue()));
        bloodOxygenDetailVO.setEndHm(DateUtils.convertDateTimeToHHMM(bloodOxygenDetail.getDailyValue()));
        return bloodOxygenDetailVO;
    }

    @Override
    public List<Integer> queryBloodOxygenSevenInfo(GeneralSecondDTO secondDTO) {
        List<RingBloodOxygenDetail> detailList = bloodOxygenDetailMapper.queryBloodOxygenSevenInfo(secondDTO.getDeviceSn(),new Date());
        List<Integer> bloodOxygens = detailList.stream().map(RingBloodOxygenDetail::getBloodOxygen).collect(Collectors.toList());
        return bloodOxygens;
    }

    /**
     * @param dateValue 时间
     * @param sleepDetail 睡眠详情对象
     * @return 时间戳与的映射列表，按时间排序
     */
    public static List<Integer> queryValue(Date dateValue,Integer timeInterval, List<Integer> valueList, RingSleepDetail sleepDetail) {
        // 转换时间单位：秒 -> 毫秒
        long intervalMs = timeInterval * 60L * 1000L;
        // 获取睡眠时间段的时间戳
        long sleepStartMs = sleepDetail.getStartDate().getTime();
        long sleepEndMs = sleepDetail.getEndDate().getTime();
        // 数据起始时间戳
        long hrStartMs = dateValue.getTime();
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < valueList.size(); i++) {
            // 计算当前数据点对应的时间戳
            long currentTimeMs = hrStartMs + (long)i * intervalMs;
            // 检查该时间点是否在睡眠期间内
            if (currentTimeMs >= sleepStartMs && currentTimeMs <= sleepEndMs) {
                int value = valueList.get(i);
                // 仅添加有效值(排除0值)
                if (value > 0) {
                    list.add(value);
                }
            }
        }
        return list;
    }
}
